﻿using Microsoft.Xna.Framework;

using block_explorer.NoiseSystem;
using block_explorer.NoiseSystem.Nodes;

namespace block_explorer
{
    class NoiseBuilder : IMapBuilder
    {
        INode mNoiseChain;

        public NoiseBuilder()
        {
            BuildNoiseChain();
        }

        public Block GetBlock(Vector3 worldPosition)
        {
            double v = mNoiseChain.Value(worldPosition.X, worldPosition.Y, worldPosition.Z);
            return new Block(v > 0.7 ? Block.ContentType.STONE : v > 0.5 ? Block.ContentType.DIRT : Block.ContentType.AIR);
            //return new Block(v > 0.5 ? Block.ContentType.STONE : Block.ContentType.AIR);
        }

        private void BuildNoiseChain()
        {
            INode baseNoise = new SimplexBasis();
            INode ridgedNoise = new Ridge(baseNoise, 1.0);

            // testing ridges
            INode terrain;
            INode test;
            {
                INode ridges = new Fractal(ridgedNoise, 4, 0.5, 0.5, 0.007, 2.0);
                INode heightmap = new ScaleDomain(ridges, 1.0, 0.0, 1.0);
                INode scaledHeightmap = new OffsetScale(heightmap, 0.0, 20.0);
                INode density = new Gradient(0, 80, 0, 0, 0, 0);
                INode hillDensity = new TranslateDomain(density, null, scaledHeightmap, null);
                INode blocks = new Select(hillDensity, 1.0, 0.0, 0.5, 0.0);

                test = hillDensity;
                terrain = blocks;
                //terrain = hillDensity;
            }

            // caves
            INode caves;
            {
                INode variedBase = new TranslateDomain(baseNoise, 732.0, -820.0, 100.0);
                INode scaledBase = new ScaleDomain(variedBase, 0.01, 0.0, 0.01);
                INode intenseBase = new OffsetScale(scaledBase, 0.0, 20.0);
                INode adjustedHillDensity = new TranslateDomain(test, null, intenseBase, null);

                INode result1 = new Fractal(ridgedNoise, 1, 1.0, 1.0, 0.04, 1.0);
                INode result2 = new TranslateDomain(result1, 500.0, 123.4, -245.1);
                INode result = new Combine(result1, result2, Combine.CombineType.Multiply);

                INode combinedDensity = new Combine(adjustedHillDensity, result, Combine.CombineType.Multiply);

                INode blocks = new Select(combinedDensity, 0.0, 1.0, 0.5, 0.0);
                //INode blocks = new OffsetScale(combinedDensity, 1.0, -1.0);

                caves = blocks;
                //caves = combinedDensity;
            }

            // mix it all together
            mNoiseChain = new Combine(terrain, caves, Combine.CombineType.Multiply);
            //mNoiseChain = terrain;
            //mNoiseChain = caves;
        }
    }
}
